module DreamSpace.System.Platform.UI {

    using
        .System.UI()
        .System.MomentJS();


    // TODO: Pre-parse (regex) each line like above and run first.  The second time the above runs it will act as a confirmation!

    /** Contains basic HTML controls as GraphItem derived classes. */
    export module HTML {

        export declare function HTMLView<T extends Node>(): HTMLView.$Type<T>;
        AppDomain.registerType("HTMLView", [DreamSpace, System, Platform, UI]);
        /** A base class for ALL HTML UI based views. */
        export module HTMLView {
            /** Each new graph item instance will initially set its '__htmlTag' property to this value. */
            export var defaultHTMLTag: string = "div";

            export class $Type<T extends Node> extends View.$Type<T> {
                // ---------------------------------------------------------------------------------------------------------------

                /** Represents the HTML element tag to use for this graph item.  The default value is set when a derived graph item is constructed.
                * Not all objects support this property, and changing it is only valid BEFORE the layout is updated for the first time.
                */
                htmlTag = HTMLView.defaultHTMLTag; // (warning: this may already be set from parsing an HTML template)
                __uiElement: T; // (DON"T INIT THIS - re-declaration of parent property)
                __uiElementParent: Node; // (DON"T INIT THIS - re-declaration of parent property)
                __asHTMLElement = <$Type<NativeTypes.IHTMLElement>><any>this;
                /** Returns true if '__uiElement' is an 'HTMLElement' DOM object (and not just a node).  Some elements (such as
                * 'PlainText') only extend directly from nodes. */
                isHTMLElement() { return this.__uiElement && this.__uiElement instanceof global.HTMLElement; }
                canAddChildren() {
                    return typeof this.__asHTMLElement.__uiElement.innerHTML !== 'undefined'; // (not all elements can have children; more info at http://www.w3schools.com/dom/dom_nodetype.asp)
                }

                // ---------------------------------------------------------------------------------------------------------------

                constructor() {
                    super();
                }

                // -------------------------------------------------------------------------------------------------------------------

                /** Changes the type of element to create (if supported by the derived type), and returns the underlying graph instance.
                * Changing this after a layout pass has already created elements will cause the existing element for this graph item to be deleted and replaced.
                * WARNING: This is not supported by all derived types, and calling this AFTER a layout pass has created elements for those unsupported types may have no effect.
                * For example, the UI 'PlaneText' graph item overrides 'createUIElement()' to return a node created from 'document.createTextNode()', 
                * and calling 'setHTMLTag("span")' will have no effect before OR after the first layout pass (this element will always be a text node).
                * Some derived types that override 'createUIElement()' my provide special logic to accept only supported types.
                */
                setHTMLTag(htmlTag: string): $Type<T> {
                    this.htmlTag = htmlTag;
                    // .. if an element already exists, replace it if the tag is different ...
                    if (this.__uiElement != null && this.__uiElement.nodeName != this.htmlTag) {
                        this.__uiElement = null;
                        this.onUpdateUIObject();
                    }
                    return this;
                }

                // -------------------------------------------------------------------------------------------------------------------

                /** The function is called in order to produce an HTML element that represents the graph item.
                * The base class, by default, simply returns a new 'HTMLDivElement' element (which doesn't display anything).
                * It is expected that implementers will override this function in derived classes if any custom UI is to be generated.
                * If the derived type doesn't represent a UI element, don't override this function.
                */
                createUIElement(): Node {
                    return document.createElement(this.htmlTag || HTMLView.defaultHTMLTag || "div");
                }

                /** Call this at the beginning of an overridden 'createUIElement()' function on a derived GraphItem type to validate supported element types. */
                assertSupportedElementTypes(...args: string[]) {
                    this.htmlTag = (this.htmlTag || "").toLowerCase();
                    //??args = <string[]><any>arguments;
                    if (args.length == 1 && typeof args[0] != 'undefined' && typeof args[0] != 'string' && args[0].length) args = <string[]><any>args[0];
                    for (var i = 0; i < args.length; i++)
                        if (this.htmlTag == args[i]) return true;
                    throw Exception.from("The element type '" + this.htmlTag + "' is not supported for this GraphItem type.");
                }

                /** Call this at the beginning of an overridden 'createUIElement()' function on a derived GraphItem type to validate unsupported element types. */
                assertUnsupportedElementTypes(...args: string[]) {
                    this.htmlTag = (this.htmlTag || "").toLowerCase();
                    //??args = <string[]><any>arguments;
                    if (args.length == 1 && typeof args[0] != 'undefined' && typeof args[0] != 'string' && args[0].length) args = <string[]><any>args[0];
                    for (var i = 0; i < args.length; i++)
                        if (this.htmlTag == args[i])
                            throw Exception.from("The element type '" + this.htmlTag + "' is not supported for this GraphItem type.");
                }

                // ---------------------------------------------------------------------------------------------------------------

                onVisualPropertyUpdated(property: Property<GraphItem.$Type, any>): void { /*virtual*/
                    super.onVisualPropertyUpdated(property);
                        // ... setting a local observable property should also set any corresponding element attribute ...
                    if (this.__asHTMLElement.__uiElement && this.__asHTMLElement.__uiElement.setAttribute)
                        this.__asHTMLElement.__uiElement.setAttribute(name, property.getValue());
               } 

                /** Called when visual-based properties have updated. */
                onUpdateVisual(): void { super.onUpdateVisual(); } /*virtual*/

                /** Triggered when the graph item is added to a parent item. */
                onAdded(): void { /*virtual*/
                    super.onAdded();
                }

                /** Triggered when the graph item is removed from a parent item. */
                onRemoved(): void { /*virtual*/
                    if (this.__uiElementParent && this.__uiElement) {
                        this.__uiElementParent.removeChild(this.__uiElement);
                        this.__uiElementParent = null;
                        this.__uiElementIndex = 0;
                    }
                    super.onRemoved();
                }

                // -------------------------------------------------------------------------------------------------------------------

                onRootChanged(oldRoot: GraphItem.$Type, newRoot: GraphItem.$Type): void { /*virtual*/
                }

                // -------------------------------------------------------------------------------------------------------------------

                onUpdateUIObject(): void { /*virtual*/
                    var parentElement: Node = this.__uiElementParent || <Node>this.getParentElement();

                    // ... create this item's element before the child items get updated ...

                    var uiObjectExists = this.__uiElement != null;
                    var uiNodeNameChanged = uiObjectExists && this.__uiElement.nodeName != this.htmlTag;

                    if (!uiObjectExists || uiNodeNameChanged) {

                        if (uiObjectExists && parentElement != null)
                            parentElement.removeChild(this.__uiElement);

                        this.__uiElement = <T>this.createUIElement();
                        this.htmlTag = this.__uiElement.nodeName; // (keep this the same, just in case it changes internally)

                        // ... apply properties as attributes ...
                        var __htmlElement = this.__asHTMLElement.__uiElement;
                        if (__htmlElement.setAttribute && this.__graphItem && this.__graphItem.__properties)
                            for (var pname in this.__graphItem.__properties) {
                                var prop = this.__graphItem.__properties[pname];
                                if (prop.hasValue())
                                    __htmlElement.setAttribute(pname, prop.getValue());
                            }
                    }
                    else if (parentElement != null && this.__uiElement.parentNode != parentElement) {
                        // ... the parent element is different for the existing element, so remove it from the current parent ...
                        this.__uiElement.parentNode.removeChild(this.__uiElement);
                    }

                    if (parentElement && this.__uiElement && this.__uiElement.parentNode != parentElement) {
                        var insertIndex = this.__uiElementIndex || this.__graphItem.__childIndex || parentElement.childNodes.length;
                        var followingElement = parentElement.childNodes[insertIndex + 1]; // (note: if 'followingElement' is null / undefined [out of bounds], the item is insert at the end)
                        parentElement.insertBefore(this.__uiElement, followingElement); // (make sure the element is inserted before any following sibling graph item's element [keep correct order!])
                    }
                }

                // -------------------------------------------------------------------------------------------------------------------

                /** Attaches an event handler to the specified event name. 
                * Any corresponding element event of the same name is also hooked into.
                */
                on(eventName: string, handler: EventHandler, eventMode: EventModes = EventModes.Capture): EventDispatcher.$Type<GraphItem.$Type, EventHandler> {
                    var existingEvent = super.on(eventName, handler, eventMode);
                    if (!existingEvent.__uiObjectHooked) {
                        var __htmlElement = this.__asHTMLElement.__uiElement;
                        if (__htmlElement) {
                            if (__htmlElement.addEventListener)
                                __htmlElement.addEventListener(eventName, (ev: any): any => { existingEvent.dispatch(ev); }, false);
                            existingEvent.__uiObjectHooked = true;
                        } else if (__htmlElement['attachEvent']) {
                            __htmlElement['attachEvent']("on" + eventName, (ev: any): any => { existingEvent.dispatch(ev); });
                            existingEvent.__uiObjectHooked = true;
                        } // (else this may be the server side, so just ignore)
                    }
                    return existingEvent;
                }

                // ---------------------------------------------------------------------------------------------------------------
            }
            AppDomain.registerClass(HTMLView);
        }

        // ===================================================================================================================

        export declare function HTMLElementBase(parent?: GraphItem.$Type): HTMLElementBase.$Type;
        //AppDomain.registerType("HTMLElementBase", [DreamSpace, System, Platform, UI]);
        /** Represents the base of a DreamSpace UI object. */
        export module HTMLElementBase {
            export var ID = Property.register(HTMLElementBase, "id", false, "");
            export var Name = Property.register(HTMLElementBase, "name", false, "");
            export var Class = Property.register(HTMLElementBase, "class", true, UNDEFINED, ClientPropertyHandlers.Class);
            export var Style = Property.register(HTMLElementBase, "style", true, UNDEFINED, ClientPropertyHandlers.Style);

            export class $Type extends GraphItem.$Type {
                // ---------------------------------------------------------------------------------------------------------------

                /* When extending 'GraphItem' with additional observable properties, it is considered good practice to create a
                * static type with a list of possible vales that can be set by end users (to promote code completion mechanisms).
                */

                _id: typeof HTMLElementBase.ID.propertyGetSetHandler;
                id: typeof HTMLElementBase.ID.defaultValue;

                _name: typeof HTMLElementBase.Name.propertyGetSetHandler;
                name: typeof HTMLElementBase.Name.defaultValue;

                _cssclass: typeof HTMLElementBase.Style.propertyGetSetHandler;
                cssclass: typeof HTMLElementBase.Style.defaultValue;

                _style: typeof HTMLElementBase.Class.propertyGetSetHandler;
                style: typeof HTMLElementBase.Class.defaultValue;

                /* (Note: This static property registration also updates an internal '__staticProeprties' list, and can be used
                * to trigger updated events for UI redraw and custom shared functionality.
                */

                // ---------------------------------------------------------------------------------------------------------------

                constructor(parent?: GraphItem.$Type) {
                    super(parent);
                }

                ///** Attaches this graph item to the specified parent object.
                //* If the object is connected to a visual element, the element will be added to its parent element also.
                //* Note: Override this in derived types that manage visual elements, and make sure to call back to this function.
                //*/
                //??attach(parent: GraphItem.$Type, index?: number): $Type;
                ///** Attach an element to this UI graph item.
                //* By default, graph items do no need a UI.  The graph system can be viewed as the "controller" (using MVC patterns) of
                //* the application, in which most (if not all) the business logic resides.  If a UI is available, then attaching an element
                //* (DOM element, or other UI type control) to a UI graph item triggers a series of events that attempt to attach all child
                //* graph items as well.  Once attached, the current Child items will automatically create their own 
                //*/
                //??attach<T extends HTMLElement>(parent: T, index?: number): $Type;
                //??attach<T extends HTMLElement>(parent: T, index?: number): $Type { /*virtual*/
                //    return <$Type>super.attach(parent, index);
                //}

                ///** Detaches this GraphItem from the graph tree (i.e. removes it from the parent object), and optionally disposes it.
                //* If the object is connected to a visual element, the element will be removed from its parent also.
                //*/
                //detach(dispose: boolean = false): $Type { /*virtual*/ // (note: this is a virtual override so the DOM elements can also be detached)
                //}

                // -------------------------------------------------------------------------------------------------------------------

                addClass(name: string) {
                    //??ClientPropertyHandlers.ClassName(name, true);
                }

                removeClass(name: string) {
                    //??ClientPropertyHandlers.ClassName(name, false);
                }

                // ---------------------------------------------------------------------------------------------------------------
            }

            AppDomain.registerClass(HTMLElementBase, [DreamSpace, System, Platform, UI]);
        }

        // ===================================================================================================================
        /** Returns a new 'HTMLElement' object. */
        export declare function HTMLElement(parent?: GraphItem.$Type, html?: string): HTMLElement.$Type { }
        //var HTMLElement: Function = <any>AppDomain.registerType<(parent?: GraphItem.$Type, html?: string) => HTMLElement.$Type>("HTMLElement", [DreamSpace, System, Platform, UI, HTML]);
        /** Represents an HTML node graph item that renders the content in the 'innerHTML of the default '__htmlTag' element (which is set to 'GraphItem.defaultHTMLTag' [DIV] initially).
        * This object has no element restrictions, so you can create any element you need by setting the '__htmlTag' tag before the UI element gets created.
        */
        export module HTMLElement {
            export var OnClick = EventDispatcher.registerEvent(HTMLElement, "click");

            export class $Type extends HTMLElementBase.$Type {

                // ---------------------------------------------------------------------------------------------------------------
                // Properties

                _html: typeof $HTMLElement.HTML.propertyGetSetHandler; // ([depreciated] to support <ES5 environments; note: this gets defined internally on the prototype, and not on the instance)
                html: typeof $HTMLElement.HTML.defaultValue; // (to support ES5 properties [IE>=9]; note: using ES5 properties may overwrite the depreciated function accessors [prefixed with '_'])

                // ---------------------------------------------------------------------------------------------------------------
                // Events

                /** Triggered when this HTML element is clicked or touched. */
                _onClick: typeof $HTMLElement.OnClick.eventFuncType;
                onClick: typeof $HTMLElement.OnClick.eventPropertyType;

                // ---------------------------------------------------------------------------------------------------------------

                _htmlChanged(property: typeof $HTMLElement.HTML.propertyType) {
                    if (!property.initialized || !this.con.__children.length) { // ('property.initialized' is false while being set to the default value for the first time - don't remove children yet in this case)
                        if (this.__children.length)
                            this.removeAllChildren();
                        try { this.__asHTMLElement.__uiElement.innerHTML = property.getValue(); }
                        catch (ex) { /*(setting inner HTML/text is not supported on this element [eg. <img> tags])*/ }
                    }
                }

                // ---------------------------------------------------------------------------------------------------------------

                constructor(parent: GraphItem.$Type = null, html: string = "") {
                    super(parent);
                    this._html(html);
                }

                // ---------------------------------------------------------------------------------------------------------------

                createUIElement(): Node {
                    return super.createUIElement();
                }

                // ---------------------------------------------------------------------------------------------------------------
            }

            export var HTML = Property.register(HTMLElement, "html", true, void 0, ClientPropertyHandlers.Element, $Type.prototype._htmlChanged);

            AppDomain.registerClass(HTMLElement, [DreamSpace, System, Platform, UI, HTML]);
        }

        // ===================================================================================================================
        
        export function Anchor(parent?: GraphItem.$Type, name?: string, href?: string, html?: string): Anchor.$Type { }
        /** Represents a basic anchor node graph item that renders a link. */
        export module Anchor {
            export var HRef = Property.register(Anchor, "href", true, <string>UNDEFINED);
            export var HRefLang = Property.register(Anchor, "hreflang", false, <string>UNDEFINED);
            export var Type = Property.register(Anchor, "type", false, <string>UNDEFINED);
            export var Rel = Property.register(Anchor, "rel", false, <string>UNDEFINED);
            export var Target = Property.register(Anchor, "target", false, <string>UNDEFINED);

            export class $Type extends __HTMLElement.HTMLElement {
                // ---------------------------------------------------------------------------------------------------------------

                _href: typeof Anchor.HRef.propertyGetSetHandler;
                href: typeof Anchor.HRef.defaultValue;

                _hreflang: typeof Anchor.HRefLang.propertyGetSetHandler;
                hreflang: typeof Anchor.HRefLang.defaultValue;

                _type: typeof Anchor.Type.propertyGetSetHandler;
                type: typeof Anchor.Type.defaultValue;

                _rel: typeof Anchor.Rel.propertyGetSetHandler;
                rel: typeof Anchor.Rel.defaultValue;

                //static Rev = Property.registerProperty(<typeof GraphItem><any>Anchor, "rev"); (not supported in HTML5)
                //rev: typeof Anchor.Rev.propertyGetSetHandler;

                //static CharSet = Property.registerProperty(<typeof GraphItem><any>Anchor, "charset"); (not supported in HTML5)
                //charset: typeof Anchor.CharSet.propertyGetSetHandler;

                _target: typeof Anchor.Target.propertyGetSetHandler;
                target: typeof Anchor.Target.defaultValue;

                // ---------------------------------------------------------------------------------------------------------------

                constructor(parent: GraphItem.$Type = null, name: string = "", href: string = "", html: string = "") {
                    super(parent, html);
                    this._name(name);
                    this._href(href);
                    this.htmlTag = "a";
                }

                // ---------------------------------------------------------------------------------------------------------------

                createUIElement(): Node {
                    this.assertSupportedElementTypes("a");
                    return super.createUIElement();
                }

                // ---------------------------------------------------------------------------------------------------------------
            }
        }
        AppDomain.registerClass(Anchor, [DreamSpace, System, Platform, UI, HTML]);

        // ===================================================================================================================

        export declare function PlainText(parent?: GraphItem.$Type, text?: string): PlainText.$Type;
        AppDomain.registerType("PlainText", [DreamSpace, System, Platform, UI, HTML]);
        /** Represents a basic text node graph item that renders plain text (no HTML). 
        * This is inline with the standard which declares that all DOM elements with text should have text-ONLY nodes.
        */
        export module PlainText {
            export class $Type extends HTMLElementBase.$Type {
                // ---------------------------------------------------------------------------------------------------------------

                _text: typeof PlainText.Text.propertyGetSetHandler;
                text: typeof PlainText.Text.defaultValue;
                _textChanged(property: typeof PlainText.Text.propertyType) {
                    (<Text>this.__uiElement).data = property.getValue();
                }

                // ---------------------------------------------------------------------------------------------------------------

                constructor(parent: GraphItem.$Type = null, text: string = "") {
                    super(parent);
                    this._text(text);
                    this.htmlTag = "";
                }

                // ---------------------------------------------------------------------------------------------------------------

                createUIElement(): Node {
                    this.assertSupportedElementTypes("", "Text");
                    return document.createTextNode("");
                }

                // ---------------------------------------------------------------------------------------------------------------
            }
            export var Text = Property.register($Type, "text", true, "", null, $Type.prototype._textChanged);
        }
        AppDomain.registerClass(PlainText);

        // ===================================================================================================================

        export declare function HTMLText(parent?: GraphItem.$Type, html?: string): HTMLText.$Type;
        AppDomain.registerType("HTMLText", [DreamSpace, System, Platform, UI, HTML]);
        /** Represents an HTML text node graph item that renders the content in the 'innerHTML of a SPAN element. 
        */
        export module HTMLText {
            export class $Type extends __HTMLElement.HTMLElement {
                // ---------------------------------------------------------------------------------------------------------------

                constructor(parent: GraphItem.$Type = null, html: string = "") {
                    super(parent, html);
                    this.htmlTag = "span";
                }

                // ---------------------------------------------------------------------------------------------------------------

                createUIElement(): Node {
                    this.assertUnsupportedElementTypes("html", "head", "body", "script", "audio", "canvas", "object");
                    return super.createUIElement();
                }

                // ---------------------------------------------------------------------------------------------------------------
            }
        }
        AppDomain.registerClass(HTMLText);

        // ===================================================================================================================

        /** A list of text mark-up flags for use with phrase based elements. */
        export enum PhraseTypes {
            /** Indicates emphasis. */
            Emphasis = 1,
            /** Indicates stronger emphasis. */
            Strong = 2,
            /** Contains a citation or a reference to other sources. */
            Cite = 4,
            /** Indicates that this is the defining instance of the enclosed term. */
            Defining = 8,
            /** Designates a fragment of computer code. */
            Code = 16,
            /** Designates sample output from programs, scripts, etc. */
            Sample = 32,
            /** Indicates text to be entered by the user. */
            Keyboard = 64,
            /** Indicates an instance of a variable or program argument. */
            Variable = 128,
            /** Indicates an abbreviated form (Example: WWW, HTTP, URI, AI, e.g., ex., etc., ...). */
            Abbreviation = 256,
            /** Indicates an acronym (Example: WAC, radar, NASA, laser, sonar, ...). */
            Acronym = 512
        }

        /** Creates a new Phrase graph item. */
        export declare function Phrase(parent?: GraphItem.$Type, phraseTypeFlags?: PhraseTypes, html?: string): Phrase.$Type;
        AppDomain.registerType("Phrase", [DreamSpace, System, Platform, UI, HTML]);
        /** Represents a basic phrase node graph item that renders phrase elements (a term used by w3.org to describe adding
        * "structural information to text fragments").  This is basically just text formatting in most cases. 
        * It's important to note the word "structural" here, as it is a suggestion on how to process text, but, unlike CSS,
        * it does not dictate exactly HOW the text will actually look like. For instance, "<STRONG>" tags usually render as
        * bold text, but someone can decide to color and increase font size instead using CSS for all such elements. This is
        * actually a good thing, as it allows flexible web design in a way that can allow applying themes at a later time. */
        export module Phrase {
            export class $Type extends HTMLText.$Type {
                // ---------------------------------------------------------------------------------------------------------------

                _phraseType: typeof Phrase.PhraseType.propertyGetSetHandler;
                phraseType: typeof Phrase.PhraseType.defaultValue;

                // ---------------------------------------------------------------------------------------------------------------

                //static createPhrase = AppDomain.registerClass<(parent?: GraphItem.$Type, phraseTypeFlags?: PhraseTypes, html?: string) => Phrase>(Phrase, DreamSpace, System, Platform, UI, HTML);

                constructor(parent: GraphItem.$Type = null, phraseTypeFlags: PhraseTypes = 0, html: string = "") {
                    super(parent, html);
                    this._phraseType(phraseTypeFlags);
                    var pInfo = this.getProperty(__HTMLElement.HTML);
                    pInfo.registerFilter(this.createPhrase);
                }

                // ---------------------------------------------------------------------------------------------------------------

                createUIElement(): Node {
                    return super.createUIElement();
                }

                // ---------------------------------------------------------------------------------------------------------------

                createPhrase(property: typeof __HTMLElement.HTML.propertyType, value: string): any {
                    var leftTags = "", rightTags = "", phraseType = this._phraseType();
                    if ((phraseType & PhraseTypes.Emphasis) > 0) { leftTags = "<em>" + leftTags; rightTags += "</em>"; }
                    if ((phraseType & PhraseTypes.Strong) > 0) { leftTags = "<strong>" + leftTags; rightTags += "</strong>"; }
                    if ((phraseType & PhraseTypes.Cite) > 0) { leftTags = "<cite>" + leftTags; rightTags += "</cite>"; }
                    if ((phraseType & PhraseTypes.Defining) > 0) { leftTags = "<dfn>" + leftTags; rightTags += "</dfn>"; }
                    if ((phraseType & PhraseTypes.Code) > 0) { leftTags = "<code>" + leftTags; rightTags += "</code>"; }
                    if ((phraseType & PhraseTypes.Sample) > 0) { leftTags = "<samp>" + leftTags; rightTags += "</samp>"; }
                    if ((phraseType & PhraseTypes.Keyboard) > 0) { leftTags = "<kbd>" + leftTags; rightTags += "</kbd>"; }
                    if ((phraseType & PhraseTypes.Variable) > 0) { leftTags = "<var>" + leftTags; rightTags += "</var>"; }
                    if ((phraseType & PhraseTypes.Abbreviation) > 0) { leftTags = "<abbr>" + leftTags; rightTags += "</abbr>"; }
                    if ((phraseType & PhraseTypes.Acronym) > 0) { leftTags = "<acronym>" + leftTags; rightTags += "</acronym>"; }
                    return leftTags + value + rightTags;
                }

                // ---------------------------------------------------------------------------------------------------------------
            }
            export var PhraseType = Property.register($Type, "phraseType", true, <PhraseTypes>0);
        }
        AppDomain.registerClass(Phrase);
        
        // ===================================================================================================================

        export declare function Header(parent?: GraphItem.$Type, html?: string): Header.$Type;
        AppDomain.registerType("Header", [DreamSpace, System, Platform, UI, HTML]);
        /** Represents an HTML header element. 
        */
        export module Header {
            export class $Type extends __HTMLElement.HTMLElement {
                // ---------------------------------------------------------------------------------------------------------------

                _headerLevel: typeof Header.HeaderLevel.propertyGetSetHandler;
                headerLevel: typeof Header.HeaderLevel.propertyType;

                // ---------------------------------------------------------------------------------------------------------------

                constructor(parent: GraphItem.$Type = null, headerLevel: number = 1, html: string = "") {
                    super(parent, html);
                    if (headerLevel < 1 || headerLevel > 6)
                        throw Exception.from("HTML only supports header levels 1 through 6.");
                    this.setValue(Header.HeaderLevel, headerLevel);
                }

                // ---------------------------------------------------------------------------------------------------------------

                createUIElement(): Node {
                    var headerLevel = this.getValue(Header.HeaderLevel);
                    if (headerLevel < 1 || headerLevel > 6)
                        throw Exception.from("HTML only supports header levels 1 through 6.");
                    this.htmlTag = "h" + headerLevel;
                    this.assertSupportedElementTypes("h1", "h2", "h3", "h4", "h5", "h6");
                    return super.createUIElement();
                }

                // ---------------------------------------------------------------------------------------------------------------
            }
            export var HeaderLevel = Property.register($Type, "headerLevel", true, 1);
        }
        AppDomain.registerClass(Header);

        // ===================================================================================================================

        export declare function Table(parent?: GraphItem.$Type): Table.$Type;
        AppDomain.registerType("Table", [DreamSpace, System, Platform, UI, HTML]);
        /** Represents a row on a table type in Bootstrap. */
        export module Table {
            export class $Type extends __HTMLElement.HTMLElement {
                // ---------------------------------------------------------------------------------------------------------------

                constructor(parent: GraphItem.$Type = null) {
                    super(parent);
                    this.htmlTag = "table";
                }

                // ---------------------------------------------------------------------------------------------------------------

                createUIElement(): Node {
                    this.assertSupportedElementTypes("table");
                    return super.createUIElement();
                }

                // ---------------------------------------------------------------------------------------------------------------
            }
        }
        AppDomain.registerClass(Table);

        // ===================================================================================================================

        export declare function TableRow(parent?: GraphItem.$Type): TableRow.$Type;
        AppDomain.registerType("TableRow", [DreamSpace, System, Platform, UI, HTML]);
        /** Represents a row on a table type in Bootstrap. */
        export module TableRow {
            export class $Type extends __HTMLElement.HTMLElement {
                // ---------------------------------------------------------------------------------------------------------------

                constructor(parent: GraphItem.$Type = null) {
                    super(parent);
                    this.htmlTag = "tr";
                }

                // ---------------------------------------------------------------------------------------------------------------

                createUIElement(): Node {
                    this.assertSupportedElementTypes("tr");
                    return super.createUIElement();
                }

                // ---------------------------------------------------------------------------------------------------------------
            }
        }
        AppDomain.registerClass(TableRow);

        // ===================================================================================================================

        export declare function TableColumn(parent?: GraphItem.$Type): TableColumn.$Type;
        AppDomain.registerType("TableColumn", [DreamSpace, System, Platform, UI, HTML]);
        /** Represents a row on a table type in Bootstrap. */
        export module TableColumn {
            export class $Type extends __HTMLElement.HTMLElement {
                // ---------------------------------------------------------------------------------------------------------------

                constructor(parent: GraphItem.$Type = null) {
                    super(parent);
                    this.htmlTag = "td";
                }

                // ---------------------------------------------------------------------------------------------------------------

                createUIElement(): Node {
                    this.assertSupportedElementTypes("td");
                    return super.createUIElement();
                }

                // ---------------------------------------------------------------------------------------------------------------
            }
        }
        AppDomain.registerClass(TableColumn);

        // ===================================================================================================================

        export declare function TableHeader(parent?: GraphItem.$Type): TableHeader.$Type;
        AppDomain.registerType("TableHeader", [DreamSpace, System, Platform, UI, HTML]);
        /** Represents a row on a table type in Bootstrap. */
        export module TableHeader {
            export class $Type extends __HTMLElement.HTMLElement {
                // ---------------------------------------------------------------------------------------------------------------

                constructor(parent: GraphItem.$Type = null) {
                    super(parent);
                    this.htmlTag = "th";
                }

                // ---------------------------------------------------------------------------------------------------------------

                createUIElement(): Node {
                    this.assertSupportedElementTypes("th");
                    return super.createUIElement();
                }

                // ---------------------------------------------------------------------------------------------------------------
            }
        }
        AppDomain.registerClass(TableHeader);

        // ===================================================================================================================
    }

}
